﻿using JESAI.Core.Aspects;
using JESAI.MonacoRoslynConplete.NuggetHandle;
using JESAI.MonacoRoslynConplete.Storages;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.Loader;
using System.Text;
using System.Threading.Tasks;

namespace JESAI.DynamicCodeRun.Run
{
    public class CodeRun
    {
        // 用于创建AssemblyLoadContext的锁对象
        private static readonly object LoadContextLock = new object();
        public static IDictionary<string, Assembly> LoadedAssemblies { get; } = new ConcurrentDictionary<string, Assembly>();

        public static void RemoveAssembly(string codeIdentify)
        {
            LoadedAssemblies.Remove(codeIdentify);
        }

        public static CodeRunResult Run(string codeIdentify, string code, string param, int languageVersion, string nuget)
        {
            languageVersion = languageVersion == 0 ? 2147483647 : languageVersion; // 默认为7，最大版本为 2147483647
            var result = new CodeRunResult();
            Assembly assembly = null;
            if (LoadedAssemblies.ContainsKey(codeIdentify))
            {
                assembly = LoadedAssemblies[codeIdentify];
            }
            else
            {
                var completeResult = CompileCode(code, codeIdentify, languageVersion, nuget);
                assembly = completeResult.assembly;
                result = completeResult.result;
            }

            // 调用动态编译的程序集
            AssemblyInvokke(assembly, param, (output) => { result.Output = output; }, (error) => { result.Error = error; }, "Handle");

            if (string.IsNullOrEmpty(result.Error))
            {
                result.ResultCode = RunResultType.Success;
            }
            else
            {
                result.ResultCode = RunResultType.Error;
            }
            return result;
        }

        public static async Task<CodeRunResult> Run(string codeIdentify, string param)
        {
            var result = new CodeRunResult();
            Assembly assembly = null;
            if (LoadedAssemblies.ContainsKey(codeIdentify))
            {
                assembly = LoadedAssemblies[codeIdentify];
            }
            else
            {
                var storage = ServiceLocator.Instance.GetService<IMonacoRoslynCompleteStorage>();
                var model = await storage.GetCodeFileContent(codeIdentify);
                var languageVersion = model.LanguageVersion == 0 ? 2147483647 : model.LanguageVersion;
                var completeResult = CompileCode(model.CodeContent, codeIdentify, languageVersion, model.NugetPackages);
                assembly = completeResult.assembly;
                result = completeResult.result;
            }

            // 调用动态编译的程序集
            AssemblyInvokke(assembly, param, (output) => { result.Output = output; }, (error) => { result.Error = error; }, "Handle");

            if (string.IsNullOrEmpty(result.Error))
            {
                result.ResultCode = RunResultType.Success;
            }
            else
            {
                result.ResultCode = RunResultType.Error;
            }
            return result;
        }

        private static (Assembly? assembly, CodeRunResult result) CompileCode(string code, string codeIdentify, int languageVersion, string nuget)
        {
            var result = new CodeRunResult();
            // 低内存版本：不使用 StringBuilder 缓存输出，只依赖回调传递实时数据
            var loadContext = new CustomAssemblyLoadContext();
            Assembly assembly = null;
            try
            {
                // 加载 NuGet 包（假设返回的包集合较小）
                var nugetAssemblies = DownloadNugetPackages.LoadPackages(nuget);

                // 设置解析选项，尽可能减小额外开销
                var parseOptions = new CSharpParseOptions(
                    languageVersion: (LanguageVersion)languageVersion,
                    kind: SourceCodeKind.Regular,
                    documentationMode: DocumentationMode.Parse
                );

                string assemblyName = "DynamicCode";

                // 解析代码
                var syntaxTree = CSharpSyntaxTree.ParseText(code, parseOptions);

                // 用循环收集引用，避免 LINQ 的额外内存分配
                var references = new List<MetadataReference>();
                foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
                {
                    if (!asm.IsDynamic && !string.IsNullOrEmpty(asm.Location))
                        references.Add(MetadataReference.CreateFromFile(asm.Location));
                }
                // 添加 NuGet 包引用
                foreach (var pkg in nugetAssemblies)
                {
                    references.Add(MetadataReference.CreateFromFile(pkg.Location));
                }

                var compilation = CSharpCompilation.Create(
                    assemblyName,
                    new[] { syntaxTree },
                    references,
                    new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
                );

                // 编译到内存流，使用完后尽快释放内存
                using (var peStream = new MemoryStream())
                {
                    var compileResult = compilation.Emit(peStream);
                    if (!compileResult.Success)
                    {
                        foreach (var diag in compileResult.Diagnostics)
                        {
                            if (diag.Severity == DiagnosticSeverity.Error)
                            {
                                result.Error = diag.ToString();
                            }
                        }
                        if (string.IsNullOrEmpty(result.Error))
                            result.Error = "Compilation error";
                        return (assembly, result);
                    }
                    peStream.Seek(0, SeekOrigin.Begin);

                    // 加载程序集（使用锁保证并发安全）
                    lock (LoadContextLock)
                    {
                        assembly = loadContext.LoadFromStream(peStream);
                        LoadedAssemblies.Add(codeIdentify, assembly);
                    }
                }
            }
            catch (Exception ex)
            {
                result.Error = ex.Message;
                return (assembly, result);
            }
            finally
            {
                // 释放资源
                if (assembly != null)
                    loadContext.Unload();
            }
            return (assembly, result);
        }
        private delegate string HandleDelegate(string param);
        private static readonly ConcurrentDictionary<MethodInfo, HandleDelegate> _handleDelegateCache = new();

        private static void AssemblyInvokke(Assembly assembly, string param, Action<string> onOutput, Action<string> onError, string method)
        {
            try
            {
                var type = assembly.GetExportedTypes()
            .LastOrDefault(t => !(t.IsAbstract && t.IsSealed));
                var methodInfo = type.GetMethod(method);
                if (methodInfo == null)
                {
                    onError("方法未找到");
                    return;
                }

                // 优先从缓存获取委托
                var handleDelegate = _handleDelegateCache.GetOrAdd(methodInfo, mi =>
                {
                    // 使用 DynamicMethod + Emit 生成委托
                    var dynamicMethod = new DynamicMethod(
                        $"Dynamic_{type.Name}_{method}",
                        typeof(string),
                        new[] { typeof(string) },
                        typeof(CodeRun).Module, // 关联到当前模块
                        skipVisibility: true);

                    var il = dynamicMethod.GetILGenerator();
                    // 对于实例方法需要加载this指针
                    if (!methodInfo.IsStatic)
                    {
                        il.Emit(OpCodes.Ldnull); // 静态方法不需要实例
                    }
                    il.Emit(OpCodes.Ldarg_0);  // 加载参数
                    il.Emit(OpCodes.Call, mi);
                    il.Emit(OpCodes.Ret);

                    return (HandleDelegate)dynamicMethod.CreateDelegate(typeof(HandleDelegate));
                });

                var result = handleDelegate(param);
                onOutput(result);
            }
            catch (Exception ex)
            {
                onError(ex.Message);
            }
        }

        // 自定义可卸载的AssemblyLoadContext
        private class CustomAssemblyLoadContext : AssemblyLoadContext
        {
            public CustomAssemblyLoadContext() : base(isCollectible: true)
            {
            }

            protected override Assembly Load(AssemblyName assemblyName)
            {
                return null; // 我们不需要从AssemblyName加载，仅从流加载
            }
        }
    }

    public class CodeRunResult
    {
        public RunResultType ResultCode { get; set; }
        public string Output { get; set; }
        public string Error { get; set; }
    }

    public enum RunResultType
    {
        Success,
        Error
    }
}
